package plus.easydo.starter.lock.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import plus.easydo.core.exception.LockFailedException;
import plus.easydo.starter.lock.annotation.RedissonLock;

import java.lang.reflect.Method;

/**
 * RedissonLock 注解拦截器
 * @author yuzhanfeng
 */
@Aspect
public class RedissonLockAspect {

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    RedissonClient redissonClient;

    @Around("@annotation(plus.easydo.starter.redis.annotation.RedissonLock)")
    public Object redissonLock(ProceedingJoinPoint point) throws Throwable {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        RedissonLock annotation = method.getAnnotation(RedissonLock.class);
        if (annotation == null) {
            return point.proceed();
        }
        RLock lock = redissonClient.getLock(annotation.key());
        try {
           boolean result =  lock.tryLock(annotation.waitTime(), annotation.leaseTime(), annotation.timeUnit());
            if (!result) {
                logger.error("线程：{} 获取锁失败",Thread.currentThread().getName());
                throw new LockFailedException(annotation.lockFailedMessage());
            }
                return point.proceed();
        } finally {
            if(lock.isLocked() && lock.isHeldByCurrentThread()){
                    lock.unlock();
            }
        }
    }


}
